{*******************************************************************************
* The contents of this file are used with permission, subject to the Mozilla   *
* Public License Version 1.1 (the "License"); you may not use this file except *
* in compliance with the License. You may obtain a copy of the License at      *
* http://www.mozilla.org/MPL/                                                  *
*                                                                              *
* Software distributed under the License is distributed on an "AS IS" basis,   *
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for *
* the specific language governing rights and limitations under the License.    *
*                                                                              *
* The Original Code is distributed as part of the "mediate" product and is     *
* Copyright (C) @home media limited. All Rights Reserved.                      *
*                                                                              *
* Email: support@athomemedia.co.uk                                             *
* Web:   http://www.athomemedia.co.uk                                          *
*******************************************************************************}

unit KeyBindings;

interface

uses XmlHelper;

const
  KEYBIND_FILENAME = 'KeyBindings.xml';

type
  TAHMKeyBindingParser = class
  private
    FParseNode: TAHMXMLNode;
    FHelper: TAHMXMLHelper;
    procedure ParseSupportedKeyProfiles;
    procedure ParseNativeKeyProfile;
    procedure ParseKeyProfiles;
  protected
    procedure LogParsingError(const sErrorCode: String);
  public
    function ParseXML(const Filepath: String): Boolean;
  end;


implementation

uses SysUtils, ApplicationManager, ActionManager, TagNames, ErrorCodes,
     AHMTypes;


function TAHMKeyBindingParser.ParseXML(const Filepath: String): Boolean;
var
  RootNode: TAHMXMLNode;
begin
  // Default result - problem loading KeyBindings configuration
  Result := False;

  // Don't bother trying to parse XML file if its missing
  if not FileExists(FilePath + KEYBIND_FILENAME) then Exit;

  FHelper := TAHMXMLHelper.Create(Filepath + KEYBIND_FILENAME);
  try
    // Ignore preamble - we're looking for a KeyBindings node
    if not FHelper.FindRootElement(RootNode, TAG_KEY_BINDINGS) then
      LogParsingError(XML_PRS_KEY_MISSING_BINDS_START_TAG);

    // What nodes do we have here?
    FParseNode := nil;
    while FHelper.NextElement(RootNode, FParseNode) do
    begin
      if FHelper.CurrentElement = TAG_SUPPORTED_PROFILES then
        ParseSupportedKeyProfiles
      else if FHelper.CurrentElement = TAG_NATIVE_KEY_PROFILE then
        ParseNativeKeyProfile
      else if FHelper.CurrentElement = TAG_KEY_PROFILES then
        ParseKeyProfiles
      else
        LogParsingError(XML_PRS_KEY_FOUND_UNKNOWN_CONTENT_TAG);
    end;

    // All is well, parsed key bindings file successfully
    Result := True;
  finally
    FHelper.Free;
  end;
end;

procedure TAHMKeyBindingParser.ParseSupportedKeyProfiles;
var
  sName, sDisp: String;
  KeyNode: TAHMXMLNode;
begin
  // Keep going as long as we find profiles to process
  KeyNode := nil;
  while FHelper.FindElement(FParseNode, KeyNode, TAG_KEY_PROFILE) do
  begin
    sName := FHelper.GetAttribute(ATTR_NAME);
    sDisp := FHelper.GetValue;

    // Add profile to list of supported key profiles
    with ApplicationManagerInstance.ActionManager.KeyProfiles.AddKeyProfile(sName) do
    begin
      DisplayText := sDisp;
    end;
  end;
end;

procedure TAHMKeyBindingParser.ParseNativeKeyProfile;
var
  sName: String;
  KeyNode: TAHMXMLNode;
begin
  // Check the keyprofile tag is there
  KeyNode := nil;
  if not FHelper.FindElement(FParseNode, KeyNode, TAG_KEY_PROFILE) then
    LogParsingError(XML_PRS_KEY_MISSING_NATIVE_PROFILE);

  // Get the name and inform action manager
  sName := FHelper.GetAttribute(ATTR_NAME);
  ApplicationManagerInstance.ActionManager.NativeKeyProfileName := sName;
end;

procedure TAHMKeyBindingParser.ParseKeyProfiles;
var
  sName, sKey, sKeyName: String;
  oProfile: TAHMKeyProfile;
  nKeyCode: Integer;
  KeyNode, ActionNode: TAHMXMLNode;
begin
  // Keep going as long as we find key profiles to process
  KeyNode := nil;
  while FHelper.FindElement(FParseNode, KeyNode, TAG_KEY_PROFILE) do
  begin
    // Get name of found profile and lookup key profile object
    sName := FHelper.GetAttribute(ATTR_NAME);
    oProfile := ApplicationManagerInstance.ActionManager.KeyProfiles.GetKeyProfile(sName);

    if not Assigned(oProfile) then
      LogParsingError(XML_PRS_KEY_UNDEFINED_PROFILE + sName);

    ActionNode := nil;

    // Keep going as long as we find action bindings to process
    while FHelper.FindElement(KeyNode, ActionNode, TAG_KEY_ACTION) do
    begin
      sName := FHelper.GetAttribute(ATTR_NAME);
      sKeyName := FHelper.GetAttribute(ATTR_KEYNAME);
      sKey := FHelper.GetValue;

      // Convert keycode to numeric value
      if (UpperCase(Copy(sKey, 1, 2)) = '0X') then
        sKey := '$' + Copy(sKey, 3, 3);
      nKeyCode := StrToIntDef(sKey, 0);

      // Add translation to relevant language object
      oProfile.AddKeyMapping(nKeyCode, sKeyName, sName);
    end;
  end;
end;


procedure TAHMKeyBindingParser.LogParsingError(const sErrorCode: String);
begin
  // Raise exception for global error handler...
  raise EConfigurationException.Create('Encountered error whilst parsing Key Bindings XML: ' + sErrorCode);
end;

end.
